

package Game;

import Drawing.TankImage;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

/**
 *
 * Compiler: jdk1.6.0_14 <br />
 * IDE: NetBeans 6.7.1 <br />
 * @author Andrew Smith <br />
 */
public class Tank
{
    /** the current x position of the center of the tank */
    private int tankX;
    /** the current y position of the center of the tank */
    private int tankY;
    /** the name of the tank (or player) */
    private String name;
    /** the current degrees the tank is facing */
    private Direction direction;
    /** a score of how many other tanks they have destroyed */
    private int score;
    /** the current shot */
    private Shot shot;
    /** the shot listener */
    private ShotListener shotlistener;
    /** a list of all the listeners listening to this object */
    private ArrayList<ActionListener> listeners;


    /**
     * Creates a new tank object to play on a game
     * @param name the name or id of the tank
     * @param x the starting x position
     * @param y the starting y position
     */
    public Tank(String name, int x, int y)
    {   this.tankX = x; this.tankY = y;
        this.name = name;
        direction = Direction.North;
        shot = null;
        score = 0;
        listeners = new ArrayList<ActionListener>();
        shotlistener = new ShotListener();
    }


    /**
     * Gets the current X position of the center of the tank
     * @return the currrent X position
     */
    public int getTankX()
    {   return tankX;
    }

    /**
     * Gets the current Y position of the center of the tank
     * @return the current Y position
     */
    public int getTankY()
    {   return tankY;
    }

    /**
     * Returns the current center point of this tank (as a point object)
     * @return the current center point
     */
    public Point getTankPoint()
    {   return new Point(tankX, tankY);
    }

    /**
     * Gets the degrees that this tank is facing
     * @return
     */
    public double getDegrees()
    {   return direction.getValue();
    }

    /**
     * Gets the direction
     * @return
     */
    public Direction getDirection()
    {   return direction;
    }

    /**
     * Gets this tank's shot (if any)
     * @return the current shot this tank has, else null if the tank has no shot
     */
    public Shot getShot()
    {   return shot;
    }


    /**
     * Sets the direction this tank is facing. Best to only call this at the start
     * @param d the new direction this tank is facing
     */
    public void setTankDirection(Direction d)
    {   this.direction = d;
    }

    /**
     * If this tanks shot hits a player, this method is called
     *
     */
    public void hitPlayer()
    {   score++;
        System.out.println("HIT PLAYER! Score: " + score);
    }

    /**
     * Makes sure the tank is still in the playing area
     * @return
     */
    public boolean isInGameBounds()
    {
        if(tankX > 0 && tankX < Match.BOUNDS_WIDTH)
        {   if(tankY > 0 && tankY < Match.BOUNDS_HEIGHT)
            {
                return true;
            }
        }
        return false;
    }

    /** this is the multiplyer for the distance the tank moves */
    private static final int movement_multiplyer = 2;

    /**
     * Moves the tank fowards relative to its current rotation
     */
    public void moveForwards()
    {
        for(int i=0; i<Direction.ROTATIONS.length; i++)
        {
            if(Direction.DIRECTIONS[i] == direction)
            {
                Point newValue = direction.getNextPointValue();
                int oldX = tankX;
                int oldY = tankY;
                tankX += newValue.x * movement_multiplyer;
                tankY += newValue.y * movement_multiplyer;
                if(!isInGameBounds())
                {
                    tankX = oldX;
                    tankY = oldY;
                }
                else
                {   notifyListeners(MOVE_FORWARDS); //notifies listeners that tank has moved forwards
                }
            }
        }
    }

    /**
     * Moves the tank backwards relative to its current rotation
     */
    public void moveBackwards()
    {
        for(int i=0; i<Direction.ROTATIONS.length; i++)
        {
            if(Direction.DIRECTIONS[i] == direction)
            {
                Point newValue = direction.getNextPointValue();
                int oldX = tankX;
                int oldY = tankY;
                tankX -= newValue.x * movement_multiplyer;
                tankY -= newValue.y * movement_multiplyer;
                if(!isInGameBounds())
                {
                    tankX = oldX;
                    tankY = oldY;
                }
                else
                {   notifyListeners(MOVE_BACKWARDS); //notifies listeners that tank has moved backwards
                }
            }
        }
    }

    /**
     * Rotates the tank to the right
     */
    public void rotateRight()
    {
        for(int i=0; i<Direction.DIRECTIONS.length; i++)
        {   if(Direction.DIRECTIONS[i] == direction)
            {
                if(i != Direction.ROTATIONS.length-1) //if it is not the last one
                {   direction = Direction.DIRECTIONS[i+1];
                    break;
                }
                else if(i == Direction.ROTATIONS.length-1)//else if it is the last one
                {   direction = Direction.North;
                    break;
                }
            }
        }
        notifyListeners(MOVE_RIGHT); //notifies listeners that tank has moved right
    }

    /**
     * Rotates the tank to the left
     */
    public void rotateLeft()
    {
        for(int i=0; i<Direction.DIRECTIONS.length; i++)
        {   if(Direction.DIRECTIONS[i] == direction)
            {
                if(i > 0) //if it is not the first one
                {   direction = Direction.DIRECTIONS[i-1];
                    break;
                }
                else if(i == 0)//else if it is the first one
                {   direction = Direction.DIRECTIONS[Direction.DIRECTIONS.length-1];
                    break;
                }
            }
        }
        notifyListeners(MOVE_LEFT); //notifies listeners that tank has moved left
    }


    /**
     * Creates a new Shot. Listens for when the shot hits something
     */
    public void shoot()
    {
        if(shot == null || !shot.isShooting())
        {
            shot = new Shot(this, direction.getDirection(), tankX, tankY);
            shot.addActionListener(shotlistener); //adds an actionlistener for this class
            notifyListeners(SHOT_MESSAGE); //notifies the listeners that this tank has fired a shot
        }
    }

    /**
     * Sets the tank to a new position (these are center coordinates)
     * @param x the new x position of the center of the tank
     * @param y the new y position of the center of the tank
     */
    public void setTankPosition(int x, int y)
    {   
        this.tankX = x; this.tankY = y;
    }




    /**
     * Adds a new listener onto this to check for updates
     * @param listener the listener to watch this shot
     */
    public void addActionListener(ActionListener listener)
    {
        listeners.add(listener);
    }


    /** an update id for actionevents */
    private int update_id = 0;
    //valid messages for the notifyListeners method
    public static final String SHOT_MESSAGE = "shot";
    public static final String MOVE_FORWARDS = "move_forward";
    public static final String MOVE_BACKWARDS = "move_backward";
    public static final String MOVE_LEFT = "move_left";
    public static final String MOVE_RIGHT = "move_right";

    /**
     * Notifies all the listeners with this
     */
    private void notifyListeners(String message)
    {
        for(int i=0; i<listeners.size(); i++)
        {
            update_id++;
            ActionEvent e = new ActionEvent(this, update_id, message);
            if(listeners.get(i)!=null)
            {   listeners.get(i).actionPerformed(e);
            }
        }
    }







    private class ShotListener implements ActionListener
    {

        public void actionPerformed(ActionEvent e)
        {
            System.out.println("SHOT!");
            notifyListeners(SHOT_MESSAGE); //notifies the listeners that this tank has fired a shot
            String message = e.getActionCommand();

            if(message.equalsIgnoreCase(Shot.HIT_PLAYER_MESSAGE)) //if the shot hit a player
            {   hitPlayer();
            }
            else if(message.equalsIgnoreCase(Shot.HIT_OBSTACLE_MESSAGE))
            {   shot = null;
            }
        }

    }
}
